function hook1(){
    // 1. 拿到基址
    var base = Module.findBaseAddress("libnative-lib.so")
    console.log("base = ",base);

    var check = base.add(0x7FC).add(0x0);
    Interceptor.attach(check,{
        onEnter:function(args){
            var input_str = args[2]
            var input_str_c = Java.vm.getEnv().getStringUtfChars(input_str)
            console.log("called enter check input_str_c = ",hexdump(input_str_c))
        },
        onLeave:function(retval){
            console.log("called leave check retval = "+retval)
        }
    })

    var sub_B90 = base.add(0xB90).add(0x0)
    Interceptor.attach(sub_B90,{
        onEnter:function(args){
            this.arg0 = args[0]
            this.arg1 = args[1]
            this.arg2 = args[2]

            console.log("called enter sub_B90 this.arg0 = "+hexdump(this.arg0)+"\nthis.arg1="+this.arg1+"\nthis.arg2"+hexdump(this.arg2))
        },
        onLeave:function(retval){
            console.log("called leave sub_B90 retval = "+retval)
            console.log("called leave sub_B90 this.arg0 = "+hexdump(this.arg0)+"\nthis.arg1="+this.arg1+"\nthis.arg2"+hexdump(this.arg2))
        }
    })

    var sub_D90 = base.add(0xD90).add(0x0)
    Interceptor.attach(sub_D90,{
        onEnter:function(args){
            this.arg0 = args[0]
            this.arg1 = args[1]

            console.log("called enter sub_D90 this.arg0 = "+hexdump(this.arg0)+"\nthis.arg1="+this.arg1)
        },
        onLeave:function(retval){
            // console.log("called leave sub_D90 this.arg0 = "+hexdump(this.arg0)+"\nthis.arg1="+this.arg1)
            console.log("called leave sub_D90 retval = "+(retval).readCString())
        }
    })

    var inline_B34 = base.add(0xB34).add(0x0)
    Interceptor.attach(inline_B34,{
        onEnter:function(args){
            // console.log("called enter inline_B34  = " + JSON.stringify(this.context))
            console.log("called enter inline_B34  = " +hexdump(this.context.x0))
            console.log("called enter inline_B34  = " +hexdump(this.context.x9))
        },
        onLeave:function(retval){
            // console.log("called leave inline_B34 this.arg0 = "+hexdump(this.arg0)+"\nthis.arg1="+this.arg1)
            // console.log("called leave sub_D90 retval = "+(retval).readCString())
        }
    })
}


function hook2(){
    Java.perform(function(){
        console.log(">>>>>>>>>>>")
        // Java.use("java.lang.String").equals.implementation = function(str){
        //     var result = this.equals(str)
        //     console.log("str = "+str);
        //     return result
        // }
        // Java.use("cn.chaitin.geektan.crackme.MainActivityPatch").Joseph.implementation = function(i,i2){
        //     var result = this.Joseph(i,i2);
        //     console.log("i = "+i+"---i2="+i2+"---result = "+result)
        //     return result;
        // }

        // console.log(Java.enumerateClassLoadersSync())
        Java.enumerateClassLoadersSync().forEach(function(loader){
            // console.log(loader)
            try{
                if(loader.loadClass("cn.chaitin.geektan.crackme.MainActivityPatch")){
                    console.log("find class " ,loader)
                    Java.classFactory.loader = loader
                            Java.use("cn.chaitin.geektan.crackme.MainActivityPatch").Joseph.implementation = function(i,i2){
                                var result = this.Joseph(i,i2);
                                console.log("i = "+i+"---i2="+i2+"---result = "+result)
                                return result;
                            }
                }
            }catch{

            }
        })
    })
}



function hook3(){
    // 1. 拿到目标so的基址
    // https://frida.re/docs/javascript-api/
    var base = Module.findBaseAddress("libwolf.so")
    console.log("base = ",base);
    // 由于该so是arm架构，所以偏移要加1
    var bc = base.add(0x14094).add(0x1)
    Interceptor.attach(bc,{
        onEnter:function(args){
            // var arg3 = args[3] // jstring
            // // https://github.com/frida/frida-java-bridge
            // var arg3_c = Java.vm.getEnv().getStringUtfChars(arg3)
            // // console.log("arg3="+hexdump(arg3_c))
            // console.log("enter bc arg3="+arg3_c.readCString())
            console.log(this.context)
        },
        onLeave:function(retval){

        }
    })

    var dc = base.add(0x14508).add(0x1)
    Interceptor.attach(dc,{
        onEnter:function(args){
            var arg2 = args[2] //
            console.log("enter dc arg2="+arg2.readCString());
        },
        onLeave:function(retval){
            console.log("leave dc retval = "+retval);
            // retval.replace(0x1)
        }
    })

    var Decrypt = base.add(0x13F34).add(0x1)
    Interceptor.attach(Decrypt,{
        onEnter:function(args){
            var arg0 = args[0] //
            var arg1 = args[1]
            console.log("enter Decrypt arg0="+arg0.readCString()+"---arg1="+hexdump(arg1));
        },
        onLeave:function(retval){
            console.log("leave Decrypt retval = "+hexdump(retval));
            // retval.replace(0x1)
        }
    })
}

function readStdString(str) {
    const isTiny = (str.readU8() & 1) == 0;
    if (isTiny) {
        return str.add(1).readUtf8String();
    }
    return str.add(2 * Process.pointerSize).readPointer().readUtf8String();
}

function callPrettyMethod(ArtMethodptr) {
    // _ZN3art9ArtMethod12PrettyMethodEPS0_b
    var PrettyMethod_addr =  Module.findExportByName("libart.so", "_ZN3art9ArtMethod12PrettyMethodEPS0_b");
    var PrettyMethodfunc = new NativeFunction(PrettyMethod_addr, ["pointer", "pointer", "pointer"], ["pointer", "int"]);
    var result = PrettyMethodfunc(ArtMethodptr, 1);
    var stdstring = Memory.alloc(3 * Process.pointerSize);
    ptr(stdstring).writePointer(result[0]);
    ptr(stdstring).add(1 * Process.pointerSize).writePointer(result[1]);
    ptr(stdstring).add(2 * Process.pointerSize).writePointer(result[2]);
    var result = readStdString(stdstring)
    return result
}

function hook_RegisterNativeMethod() {
    var RegisterNativeMethod_addr = Module.findExportByName("libart.so", "_ZN3art16RuntimeCallbacks20RegisterNativeMethodEPNS_9ArtMethodEPKvPPv");
    console.log("RegisterNativeMethod_addr=",RegisterNativeMethod_addr)
    // art::RuntimeCallbacks::RegisterNativeMethod(art::ArtMethod*, void const*, void**)
    Interceptor.attach(RegisterNativeMethod_addr, {
        onEnter: function (args) {
            this.artmethod = args[1];
            var methodname = callPrettyMethod(ptr(this.artmethod));
            var address = args[2];
            this.dex_method_index_ = ptr(this.artmethod).add(12).readU32();
            var current_module = Process.getModuleByAddress(address)
            var modulename = current_module.name
            var base = current_module.base
            var offset = address.sub(base)
            console.log("go into RegisterNativeMethod ---" + "artmethodptr:" + ptr(this.artmethod) + "---methodidx:" + this.dex_method_index_ + "--addr:" + address + "----name:" + methodname + "---modulename:" + modulename + "---offset:" + offset);
            return;
        }, onLeave: function (retval) {
        }
    })
}



function hook_RegisterNatives() {
    var symbols = Module.enumerateSymbolsSync("libart.so");
    var addrRegisterNatives = null;
    for (var i = 0; i < symbols.length; i++) {
        var symbol = symbols[i];

        //_ZN3art3JNI15RegisterNativesEP7_JNIEnvP7_jclassPK15JNINativeMethodi
        if (symbol.name.indexOf("art") >= 0 &&
                symbol.name.indexOf("JNI") >= 0 &&
                symbol.name.indexOf("RegisterNatives") >= 0 &&
                symbol.name.indexOf("CheckJNI") < 0) {
            addrRegisterNatives = symbol.address;
            console.log("RegisterNatives is at ", symbol.address, symbol.name);
        }
    }

    if (addrRegisterNatives != null) {
        Interceptor.attach(addrRegisterNatives, {
            onEnter: function (args) {
                console.log("[RegisterNatives] method_count:", args[3]);
                var env = args[0];
                var java_class = args[1];
                var class_name = Java.vm.tryGetEnv().getClassName(java_class);
                //console.log(class_name);

                var methods_ptr = ptr(args[2]);

                var method_count = parseInt(args[3]);
                for (var i = 0; i < method_count; i++) {
                    var name_ptr = Memory.readPointer(methods_ptr.add(i * Process.pointerSize * 3));
                    var sig_ptr = Memory.readPointer(methods_ptr.add(i * Process.pointerSize * 3 + Process.pointerSize));
                    var fnPtr_ptr = Memory.readPointer(methods_ptr.add(i * Process.pointerSize * 3 + Process.pointerSize * 2));

                    var name = Memory.readCString(name_ptr);
                    var sig = Memory.readCString(sig_ptr);
                    var find_module = Process.findModuleByAddress(fnPtr_ptr);
                    console.log("[RegisterNatives] java_class:", class_name, "name:", name, "sig:", sig, "fnPtr:", fnPtr_ptr, "module_name:", find_module.name, "module_base:", find_module.base, "offset:", ptr(fnPtr_ptr).sub(find_module.base));

                }
            }
        });
    }
}

setImmediate(hook_RegisterNativeMethod);

